﻿using System;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Text;
using System.Threading;

namespace Bible.UI.CLI.IntegrationTests
{
    internal class CLIRunner : IDisposable
    {
        private Process process;
        private StringWriter console;
        private StringBuilder stringBuilder;
        private TextWriter systemOutput;
        private CultureInfo systemCulture;
        private CultureInfo systemUICulture;

        private readonly string filePrefix = "file:\\";

        /// <summary>
        /// Command Line Interface program runner.
        /// </summary>
        /// <param name="executable">Process filename.</param>
        /// <param name="cultureInfo">set UI Culture of thread.</param>
        /// <param name="arguments">Command line arguments.</param>
        public CLIRunner(string executable,
                         CultureInfo cultureInfo,
                         string arguments = "")
        {
            Initialize(executable, cultureInfo, arguments);
        }

        public int Run()
        {
            process.Start();
            process.WaitForExit();

            return process.ExitCode;
        }

        private void Initialize(string executable, CultureInfo cultureInfo, string arguments)
        {
            stringBuilder = new StringBuilder();
            console = new StringWriter(stringBuilder);

            systemOutput = System.Console.Out;
            Console.SetOut(console);

            process = new Process();

            systemCulture = Thread.CurrentThread.CurrentCulture;
            systemUICulture = Thread.CurrentThread.CurrentUICulture;

            Thread.CurrentThread.CurrentCulture = cultureInfo;
            Thread.CurrentThread.CurrentUICulture = cultureInfo;

            string directoryName =
                Path.GetDirectoryName(
                    Assembly.GetExecutingAssembly().CodeBase);

            if (directoryName.StartsWith(filePrefix))
                directoryName = directoryName.Substring(filePrefix.Length);

            Environment.CurrentDirectory = directoryName;

            process.StartInfo.FileName = executable;
            process.StartInfo.Arguments = arguments;
            process.StartInfo.UseShellExecute = false;
            process.StartInfo.RedirectStandardOutput = true;
            process.StartInfo.RedirectStandardError = true;
            process.StartInfo.WorkingDirectory = Environment.CurrentDirectory;
        }

        public string Output
        {
            get
            {
                DumpOutput();
                return stringBuilder.ToString();
            }
        }

        private void DumpOutput()
        {
            Console.WriteLine(process.StandardOutput.ReadToEnd());
            Console.Write(process.StandardError.ReadToEnd());
        }

        private void Exit()
        {
            Thread.CurrentThread.CurrentCulture = systemCulture;
            Thread.CurrentThread.CurrentUICulture = systemUICulture;

            Console.SetOut(systemOutput);
        }

        #region IDisposable Members

        public void Dispose()
        {
            Exit();
            console.Dispose();
            systemOutput.Dispose();
            process.Dispose();
        }

        #endregion IDisposable Members
    }
}